interface EventCallback {
  (...args: any[]): any
}

class EventBus<E = any> {
  private listeners: Map<E, EventCallback[]> = new Map()

  on(eventName: E, callback: EventCallback): void {
    const callbacks = this.listeners.get(eventName)
    if (callbacks) {
      callbacks.push(callback)
    }
    else {
      this.listeners.set(eventName, [callback])
    }
  }

  emit<T = any>(eventName: E, data?: T): void {
    const callbacks = this.listeners.get(eventName)
    if (callbacks) {
      callbacks.forEach((callback) => {
        callback(data)
      })
    }
  }
}

function createEventBus<E>(): EventBus<E> {
  return new EventBus<E>()
}

export type {
  EventCallback,
}

export { createEventBus, EventBus }
